#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
样本数据推送服务
负责将样本数据转换为JSON格式并推送给TCP客户端
"""

import json
import logging
from datetime import datetime
from typing import List, Dict, Optional
from PyQt6.QtCore import QObject, pyqtSignal

try:
    from src.utils.json_encoder import safe_json_dumps, JSONErrorHandler
except ImportError:
    try:
        from ..utils.json_encoder import safe_json_dumps, JSONErrorHandler
    except ImportError:
        # 如果导入失败，使用标准json模块
        def safe_json_dumps(data, **kwargs):
            return json.dumps(data, ensure_ascii=False, default=str, **kwargs)
        
        class JSONErrorHandler:
            @staticmethod
            def handle_encoding_error(data, error):
                return json.dumps(data, ensure_ascii=True, default=str)

try:
    from src.models.models import Sample
    from src.protocols.tcp.tcp_server import TCPServer
    from src.utils.logger_manager import get_system_logger, OperationType
except ImportError:
    try:
        from ..models.models import Sample
        from ..protocols.tcp.tcp_server import TCPServer
        from ..utils.logger_manager import get_system_logger, OperationType
    except ImportError:
        Sample = None
        TCPServer = None
        get_system_logger = None
        OperationType = None

logger = logging.getLogger(__name__)

class SamplePushService(QObject):
    """样本数据推送服务"""
    
    # 信号定义
    push_started = pyqtSignal(int)  # 推送开始信号 (样本数量)
    push_progress = pyqtSignal(int, int)  # 推送进度信号 (当前数量, 总数量)
    push_completed = pyqtSignal(int, int)  # 推送完成信号 (成功数量, 总数量)
    push_error = pyqtSignal(str)  # 推送错误信号
    
    def __init__(self, tcp_server: TCPServer = None):
        super().__init__()
        self.tcp_server = tcp_server
        self.is_pushing = False
        
        # 系统日志管理器
        self.system_logger = get_system_logger() if get_system_logger else None
        
        # 记录服务初始化日志
        if self.system_logger:
            self.system_logger.log_system_event(
                "样本推送服务初始化",
                "样本推送服务已初始化完成",
                details={"tcp_server_available": tcp_server is not None}
            )
    
    def set_tcp_server(self, tcp_server: TCPServer):
        """设置TCP服务器"""
        self.tcp_server = tcp_server
    
    def convert_sample_to_json(self, sample: Sample, include_full_database: bool = True) -> Dict:
        """将样本对象转换为JSON格式，包含完整的数据库内容"""
        try:
            if not sample:
                return {}
            
            # 完整的样本数据结构
            sample_data = {
                # 基础样本信息
                "sample_id": sample.id,
                "sample_number": sample.sample_info.sample_number,
                "patient_name": sample.sample_info.patient_name,
                "patient_id": sample.sample_info.sample_id,
                "patient_age": sample.sample_info.patient_age,
                "patient_gender": sample.sample_info.patient_gender,
                "sample_type": sample.sample_info.sample_type,
                "collection_time": sample.sample_info.datetime,
                "received_time": sample.receive_time.isoformat() if sample.receive_time else None,
                "status": sample.status.value if hasattr(sample.status, 'value') else str(sample.status),
                "priority": "普通",  # 默认优先级
                "notes": "",
                "created_time": sample.created_time.isoformat() if sample.created_time else None,
                "updated_time": sample.updated_time.isoformat() if sample.updated_time else None,
                
                # 协议和仪器信息
                "protocol": sample.protocol if hasattr(sample, 'protocol') else "CUSTOM_LIS",
                "machine_model": sample.machine_model if hasattr(sample, 'machine_model') else "",
                "machine_id": sample.machine_id if hasattr(sample, 'machine_id') else "",
                
                # 完整的样本信息对象
                "sample_info": {
                    "sample_number": sample.sample_info.sample_number,
                    "patient_name": sample.sample_info.patient_name,
                    "sample_id": sample.sample_info.sample_id,
                    "patient_age": sample.sample_info.patient_age,
                    "patient_gender": sample.sample_info.patient_gender,
                    "sample_type": sample.sample_info.sample_type,
                    "sample_type_name": sample.sample_info.sample_type_name,
                    "sample_category": sample.sample_info.sample_category,
                    "report_id": sample.sample_info.report_id,
                    "position": sample.sample_info.position,
                    "datetime": sample.sample_info.datetime
                },
                
                # 完整的检测结果对象
                "results": {},
                
                # 图片信息
                "image": {},
                
                # 原始数据库字段（如果存在）
                # "raw_data": {}
            }
            
            # 检测结果 - 包含所有字段
            if hasattr(sample, 'results') and sample.results:
                # 基础检测项目
                basic_items = [
                    ('HbA1a', sample.results.HbA1a),
                    ('HbA1b', sample.results.HbA1b),
                    ('HbF', sample.results.HbF),
                    ('LA1c', sample.results.LA1c),
                    ('HbA1c', sample.results.HbA1c),
                    ('HbA0', sample.results.HbA0),
                    ('eAG', sample.results.eAG)
                ]
                
                # 变异筛查项目
                variant_items = [
                    ('A2', sample.results.A2),
                    ('HbE', sample.results.HbE),
                    ('HbD', sample.results.HbD),
                    ('HbS', sample.results.HbS),
                    ('HbC', sample.results.HbC),
                    ('p3', sample.results.p3),
                    ('v-win', sample.results.v_win)
                ]
                
                # 构建完整的检测结果对象
                results_data = {}
                
                # 添加基础检测项目
                for name, value in basic_items:
                    results_data[name] = str(value) if value is not None else None
                
                # 添加变异筛查项目
                for name, value in variant_items:
                    results_data[name] = str(value) if value is not None else None
                
                # 添加TIME和AREA数据
                if hasattr(sample.results, 'TIME') and sample.results.TIME:
                    results_data["TIME"] = sample.results.TIME
                if hasattr(sample.results, 'AREA') and sample.results.AREA:
                    results_data["AREA"] = sample.results.AREA
                
                # 添加TIME_DETAILS和AREA_DETAILS
                if hasattr(sample.results, 'TIME_DETAILS') and sample.results.TIME_DETAILS:
                    results_data["TIME_DETAILS"] = sample.results.TIME_DETAILS
                if hasattr(sample.results, 'AREA_DETAILS') and sample.results.AREA_DETAILS:
                    results_data["AREA_DETAILS"] = sample.results.AREA_DETAILS
                
                # 添加其他结果字段
                # if hasattr(sample.results, 'other_results') and sample.results.other_results:
                #     results_data["other_results"] = sample.results.other_results
                
                # 添加检测结果的时间戳信息
                results_data["test_time"] = sample.receive_time.isoformat() if sample.receive_time else None
                
                sample_data["results"] = results_data
                
                # 同时保留原有的test_results格式以保持兼容性
                test_results = []
                
                # 定义检测项目及其单位
                analyte_units = {
                    'HbA1a': '%', 'HbA1b': '%', 'HbF': '%', 'LA1c': '%', 'HbA1c': '%', 
                    'HbA0': '%', 'p3': '%', 'A2': '%', 'HbE': '%', 'HbD': '%', 
                    'HbS': '%', 'HbC': '%', 'eAG': 'mg/dL', 'v-win': '%'
                }
                
                for name, value in basic_items + variant_items:
                    if value:
                        unit = analyte_units.get(name, '%')  # 默认单位为%
                        test_result = {
                            "test_name": name,
                            "result_value": str(value),
                            "unit": unit,
                            "reference_range": "",
                            "is_abnormal": False,
                            "test_time": sample.receive_time.isoformat() if sample.receive_time else None,
                            "operator": "",
                            "notes": ""
                        }
                        test_results.append(test_result)
                
                sample_data["test_results"] = test_results
            
            # 图片信息 - 包含base64数据和完整信息
            if hasattr(sample, 'image') and sample.image:
                # 获取base64数据，优先级：base64_data > hex_data > 从文件路径读取
                base64_data = None
                
                # 1. 首先尝试使用已有的base64_data
                if hasattr(sample.image, 'base64_data') and sample.image.base64_data:
                    base64_data = sample.image.base64_data
                    logger.info(f"使用已有的base64_data，长度: {len(base64_data)}")
                
                # 2. 如果没有base64_data，尝试从hex_data转换
                elif hasattr(sample.image, 'hex_data') and sample.image.hex_data:
                    try:
                        import base64
                        hex_data = sample.image.hex_data.replace(' ', '').replace('\n', '').replace('\r', '')
                        if len(hex_data) % 2 == 0:  # 确保hex数据长度是偶数
                            binary_data = bytes.fromhex(hex_data)
                            base64_data = base64.b64encode(binary_data).decode('utf-8')
                            logger.info(f"成功将hex_data转换为base64，长度: {len(base64_data)}")
                    except Exception as e:
                        logger.warning(f"hex_data转换为base64失败: {e}")
                
                # 3. 如果前两种方法都失败，尝试从文件路径读取图片并转换为base64
                if not base64_data and hasattr(sample.image, 'path') and sample.image.path:
                    try:
                        import base64
                        import os
                        
                        # 检查文件是否存在
                        if os.path.exists(sample.image.path):
                            with open(sample.image.path, 'rb') as image_file:
                                image_bytes = image_file.read()
                                base64_data = base64.b64encode(image_bytes).decode('utf-8')
                                logger.info(f"成功从文件路径读取图片并转换为base64，文件: {sample.image.path}，长度: {len(base64_data)}")
                        else:
                            logger.warning(f"图片文件不存在: {sample.image.path}")
                    except Exception as e:
                        logger.error(f"从文件路径读取图片失败: {sample.image.path}, 错误: {e}")
                
                image_data = {
                    # "filename": base64_data,  # filename字段直接使用base64数据
                    "size": sample.image.size if hasattr(sample.image, 'size') else None,
                    "path": sample.image.path if hasattr(sample.image, 'path') else None,
                    "saved": sample.image.saved if hasattr(sample.image, 'saved') else None,
                    "hex_data": sample.image.hex_data if hasattr(sample.image, 'hex_data') else None,
                    "base64_data": base64_data,
                    "error": sample.image.error if hasattr(sample.image, 'error') else None
                }
                sample_data["image"] = image_data
                
                # 保持向后兼容
                if hasattr(sample.image, 'path') and sample.image.path:
                    sample_data["image_path"] = sample.image.path
            
            # 添加原始数据库字段（如果存在其他字段）
            # if hasattr(sample, '__dict__'):
            #     raw_data = {}
            #     for key, value in sample.__dict__.items():
            #         if not key.startswith('_') and key not in ['id', 'sample_info', 'results', 'image', 'receive_time', 'status', 'created_time', 'updated_time']:
            #             if hasattr(value, 'isoformat'):
            #                 raw_data[key] = value.isoformat()
            #             else:
            #                 raw_data[key] = str(value) if value is not None else None
            #     sample_data["raw_data"] = raw_data
            
            return sample_data
            
        except Exception as e:
            logger.error(f"转换样本数据失败: {e}")
            return {}
    
    def push_single_sample(self, sample: Sample, client_id: str = None, include_full_database: bool = True) -> bool:
        """推送单个样本数据"""
        try:
            if not self.tcp_server:
                logger.error("TCP服务器未设置")
                return False
            
            # 转换样本数据
            sample_json = self.convert_sample_to_json(sample, include_full_database)
            if not sample_json:
                logger.error("样本数据转换失败")
                return False
            
            # 记录数据推送日志
            if self.system_logger:
                try:
                    data_size = len(safe_json_dumps(sample_json))
                except Exception as e:
                    logger.warning(f"计算数据大小失败: {e}")
                    data_size = 0
                
                self.system_logger.log_data_reception(
                    "样本推送",
                    f"推送样本 {sample.id}",
                    source="样本推送服务",
                    details={
                        "sample_id": sample.id,
                        "client_id": client_id,
                        "data_size": data_size,
                        "operation": "push"
                    }
                )
            
            # 发送数据
            success = self.tcp_server.send_json_to_client(client_id, sample_json)
            
            if success:
                logger.info(f"样本 {sample.id} 推送成功")
            else:
                logger.error(f"样本 {sample.id} 推送失败")
                
                # 记录推送失败日志
                if self.system_logger:
                    self.system_logger.log_communication_event(
                        "样本推送失败",
                        f"样本 {sample.id} 推送失败",
                        connection_info={"client_id": client_id, "type": "TCP"},
                        success=False
                    )
            
            return success
            
        except Exception as e:
            logger.error(f"推送样本数据失败: {e}")
            
            # 记录推送失败日志
            if self.system_logger:
                self.system_logger.log_communication_event(
                    "样本推送异常",
                    f"推送样本数据失败: {str(e)}",
                    connection_info={"client_id": client_id, "type": "TCP"},
                    success=False
                )
            return False
    
    def push_sample_batch(self, samples: List[Sample], client_id: str = None, include_full_database: bool = True) -> Dict[str, int]:
        """批量推送样本数据"""
        if not samples:
            return {"success": 0, "failed": 0, "total": 0}
        
        self.is_pushing = True
        total_count = len(samples)
        success_count = 0
        failed_count = 0
        
        # 记录批量推送开始日志
        if self.system_logger:
            self.system_logger.log_system_event(
                "批量样本推送开始",
                f"开始批量推送 {total_count} 个样本",
                details={
                    "total_count": total_count,
                    "client_id": client_id
                }
            )
        
        try:
            # 发送推送开始信号
            self.push_started.emit(total_count)
            
            for i, sample in enumerate(samples):
                if not self.is_pushing:
                    break
                
                # 发送进度信号
                self.push_progress.emit(i + 1, total_count)
                
                # 推送单个样本
                if self.push_single_sample(sample, client_id, include_full_database):
                    success_count += 1
                else:
                    failed_count += 1
                
                # 添加延迟，避免发送过快
                import time
                time.sleep(0.1)  # 100ms延迟
            
            # 记录批量推送完成日志
            if self.system_logger:
                self.system_logger.log_system_event(
                    "批量样本推送完成",
                    f"批量推送完成: 成功 {success_count}, 失败 {failed_count}, 总计 {total_count}",
                    details={
                        "success_count": success_count,
                        "failed_count": failed_count,
                        "total_count": total_count,
                        "client_id": client_id
                    }
                )
            
            # 发送推送完成信号
            self.push_completed.emit(success_count, total_count)
            
            return {
                "success": success_count,
                "failed": failed_count,
                "total": total_count
            }
            
        except Exception as e:
            logger.error(f"批量推送样本数据失败: {e}")
            
            # 记录批量推送失败日志
            if self.system_logger:
                self.system_logger.log_system_event(
                    "批量样本推送失败",
                    f"批量推送样本数据失败: {str(e)}",
                    details={
                        "total_count": total_count,
                        "client_id": client_id,
                        "error": str(e)
                    }
                )
            
            # 发送推送错误信号
            self.push_error.emit(str(e))
            
            return {
                "success": success_count,
                "failed": failed_count,
                "total": total_count
            }
        finally:
            self.is_pushing = False
    
    def cancel_push(self):
        """取消推送"""
        self.is_pushing = False
        logger.info("推送已取消")
    
    def get_push_status(self) -> bool:
        """获取推送状态"""
        return self.is_pushing
    
    def get_connected_clients(self) -> List[str]:
        """获取已连接的客户端列表"""
        if self.tcp_server:
            return self.tcp_server.get_client_list()
        return []
    
    def get_client_count(self) -> int:
        """获取客户端数量"""
        if self.tcp_server:
            return self.tcp_server.get_client_count()
        return 0 